package values;

import instructions.BadInstructionException;
import instructions.Instruction;
import base.Environment;
import base.Identifier;

public class Function implements Value {

	private Instruction body;
	private Environment context;
	private Identifier args[];

	/**
	 * Creates a new function with body 'body', contextual environment 'context'
	 * and with identifiers 'args' for the function's arguments
	 * 
	 * @param body
	 * @param context
	 * @param args
	 */

	public Function(Instruction body, Environment context, Identifier args[]) {
		this.body = body;
		this.context = context;
		this.args = args;
	}

	/**
	 * Executes the function with values argsValues as arguments. Returns an
	 * array of Value corresponding to the arguments value at the end of the
	 * function. This is how the function returns values to who ever called it.
	 * 
	 * @param argsValues
	 * @return
	 * @throws BadInstructionException
	 */

	public Value[] execute(Value argsValues[]) throws BadInstructionException {
		assert argsValues.length == this.args.length;

		Environment curContext = this.context.clone();

		if (this.args != null)
			for (int i = 0; i < this.args.length; i++)
				curContext.update(this.args[i], argsValues[i]);

		Environment resultEnv = this.body.instr(curContext);

		Value resultArgs[] = null;

		if (this.args != null) {
			resultArgs = new Value[this.args.length];

			for (int i = 0; i < this.args.length; i++)
				resultArgs[i] = resultEnv.getValue(this.args[i]);
		}

		return resultArgs;
	}

}
